#include "../headers/main.h"
#include "../headers/glossaire.h"
#include "../headers/generation.h"
#include "../headers/outils.h"
#include "../headers/forces_symboliques.h"

char* generationJeu(unsigned char nb_cartes_a_enlever, ...) {
    /* Génération d'un jeu de 52 cartes
     * Une carte est codée sur 6 bits
     * Stockée sur 8 bits (valeur minimum => char)
     * Les 2 derniers bits représentent la couleur
     * Les 4 d'avant la valeur
     * 
     * Note : les parametres sont les cartes à enlever du jeu
     */
    char* jeu = malloc((NB_CARTES+1) * sizeof(char));
    char tmp_carte = '\0';
    *(jeu + NB_CARTES) = '\0';
    
    unsigned char couleurs[4] = { TREFLE, COEUR, PIQUE, CARREAU };
    unsigned char valeurs[13] = { AS, DEUX, TROIS, QUATRE, CINQ, SIX, SEPT, HUIT, NEUF, DIX, VALET, DAME, ROI };
    
    unsigned char i,j,k,a_ne_pas_enlever = 0,numcarte = 0;
    
    //Récupération des cartes à enlever
    char* cartes_a_enlever = malloc((nb_cartes_a_enlever+1) * sizeof(char));
    va_list ap;
    va_start(ap, nb_cartes_a_enlever);
    for (i=0;i<nb_cartes_a_enlever;i++) {
        *(cartes_a_enlever + i) = va_arg(ap, int);
    }
    *(cartes_a_enlever + nb_cartes_a_enlever) = '\0';
    va_end(ap);
    
    for (i=0; i < NB_COULEURS; i++) {
        for (j=0; j < NB_VALEURS; j++) {
            assert(numcarte<NB_CARTES);
            tmp_carte = (*(valeurs + j) | *(couleurs + i)); //Génération de la valeur binaire de la carte
            
            for (k=0;k<nb_cartes_a_enlever;k++) {
                if (tmp_carte == *(cartes_a_enlever + k)) {
                    a_ne_pas_enlever=1;
                }
            }
            
            if (!a_ne_pas_enlever) {
                *(jeu + numcarte) = tmp_carte;
                numcarte++;
            }
            
            a_ne_pas_enlever=0;
            
        }

    
    }
    
    return jeu;

}


char** generationMains5cartes(char* jeu) {
    /* Génération de toutes les mains (combinaisons) de 5 cartes possibles
     * Une combinaison est codée sur 5 octets (on peut optimiser à 4 octets car 6*5=30bits)
     * Chaque octet représente une carte
     * 
     */
    char** listeMains = malloc(0);
    unsigned char nb_cartes;
    
    //On calcule le nombre de cartes dans le jeu
    for (nb_cartes=0;jeu[nb_cartes]!='\0';nb_cartes++);
    
    
    unsigned char i,j,k,l,m;
    unsigned long long nb=0;
    
    for (i=0; i<nb_cartes; i++) {
        
        for (j=i+1; j<nb_cartes; j++) {

            for (k=j+1; k<nb_cartes; k++) {

                for (l=k+1; l<nb_cartes; l++) {
                     
                    for (m=l+1; m<nb_cartes; m++) {
                        listeMains = realloc(listeMains, sizeof(listeMains) * (nb+1));
                        listeMains[nb] = malloc( sizeof(char) * 6 );
                        listeMains[nb][0] = jeu[i];
                        listeMains[nb][1] = jeu[j];
                        listeMains[nb][2] = jeu[k];
                        listeMains[nb][3] = jeu[l];
                        listeMains[nb][4] = jeu[m];
                        listeMains[nb][5] = '\0';
                        nb++;
                    }   
                    
                }   
                
            }
        
        }
        
    }
    listeMains = realloc(listeMains, sizeof(listeMains) * (nb+1));
    *(listeMains + nb) = NULL;
    return listeMains;
}

void ajouterPuissanceForce(Puissance** puissances,char* force,unsigned int * nb_puissances) {
    unsigned long long int puissance = getPuissanceForce(force);
    unsigned int i;
    for (i=0;i<(*nb_puissances);i++) {
        if (puissances[i]->puissance == puissance) {
            puissances[i]->nb++;
            return;
        }
    }
    (*nb_puissances)++;
    //puissances = realloc(puissances,*nb_puissances * sizeof(Puissance*) );
    Puissance* une_puissance = malloc(sizeof(Puissance));
    une_puissance->nb = 1;
    une_puissance->puissance = puissance;   
    puissances[i] = une_puissance;
    return;
}
Puissance** generationFuturesPuissances(char* jeu, int nb_cartes_a_inclure, ...) {
    //Retourne un tableau de puissances contenant les futures puissances des mains
    Puissance** futures_puissances = malloc(10000);
    
    //On calcule le nombre de cartes dans le jeu
    int nb_cartes;
    for (nb_cartes=0;jeu[nb_cartes]!='\0';nb_cartes++);
    
    int i,j,k,l,m;
    
    char* une_main = malloc(8*sizeof(char));
    for (i=0;i<8;i++) { une_main[i] = '\0'; }
    
    va_list ap;
    va_start(ap, nb_cartes_a_inclure);
    for (i=0;i<nb_cartes_a_inclure;i++) { *(une_main + i) = va_arg(ap, int); }
    va_end(ap);   
    
    char* sa_force = malloc(7*sizeof(char));
    unsigned int nb_puissances = 0;
    
    if (nb_cartes_a_inclure == 6) {
        for (i=0; i<nb_cartes; i++) {
            une_main[6] = jeu[i];
            getForceSymbolique(une_main,sa_force);
            ajouterPuissanceForce(futures_puissances,sa_force,&nb_puissances);
        }
    }
    else if (nb_cartes_a_inclure == 5) {
        for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                une_main[5] = jeu[i];
                une_main[6] = jeu[j];
                getForceSymbolique(une_main,sa_force);
                ajouterPuissanceForce(futures_puissances,sa_force,&nb_puissances);
            }
        }
    }
    else if (nb_cartes_a_inclure == 4) {
         for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                for (k=j+1; k<nb_cartes; k++) {
                    une_main[4] = jeu[i];
                    une_main[5] = jeu[j];                          
                    une_main[6] = jeu[k];
                    getForceSymbolique(une_main,sa_force);
                    ajouterPuissanceForce(futures_puissances,sa_force,&nb_puissances);
                }
            }
        }        
    }
    else if (nb_cartes_a_inclure == 3) {
         for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                for (k=j+1; k<nb_cartes; k++) {
                    for (l=k+1; l<nb_cartes; l++) {
                        une_main[3] = jeu[i];
                        une_main[4] = jeu[j];                          
                        une_main[5] = jeu[k];                          
                        une_main[6] = jeu[l]; 
                        getForceSymbolique(une_main,sa_force);
                        ajouterPuissanceForce(futures_puissances,sa_force,&nb_puissances);
                    }
                }
            }
        }        
    }
    else if (nb_cartes_a_inclure == 2) {
        //On génère les flops, turns et les rivers
        for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                for (k=j+1; k<nb_cartes; k++) {
                    for (l=k+1; l<nb_cartes; l++) {
                        for (m=l+1; m<nb_cartes; m++) {
                            une_main[2] = jeu[i];
                            une_main[3] = jeu[j];                          
                            une_main[4] = jeu[k];                          
                            une_main[5] = jeu[l];                          
                            une_main[6] = jeu[m]; 
                            getForceSymbolique(une_main,sa_force);
                            ajouterPuissanceForce(futures_puissances,sa_force,&nb_puissances);
                        }
                    }
                }
            }
        }       
    }
    free(une_main);
    free(sa_force);

    return futures_puissances;
}


char** generationMains7cartes(char* jeu, int nb_cartes_a_inclure, ...) {
    /* Génération de toutes les mains (combinaisons) de 7 cartes possibles
     * Une combinaison est codée sur 5 octets (on peut optimiser à 4 octets car 6*5=30bits)
     * Chaque octet représente une carte
     */
    
    //On calcule le nombre de cartes dans le jeu
    int nb_cartes;
    for (nb_cartes=0;jeu[nb_cartes]!='\0';nb_cartes++);
    
    //On calcule le nombre de mains à générer, et on alloue la memoire
    unsigned long int nb_mains = getNbMainsAGenerer(nb_cartes,nb_cartes_a_inclure);

    char** listeMains = (char**)malloc((nb_mains+1) * sizeof(char*));
    

    int i,j,k,l,m;
    
    
    char* une_main = malloc(8*sizeof(char));
    for (i=0;i<8;i++) { une_main[i] = '\0'; }
    
    va_list ap;
    va_start(ap, nb_cartes_a_inclure);
    for (i=0;i<nb_cartes_a_inclure;i++) {
       *(une_main + i) = va_arg(ap, int);
    }
    va_end(ap);   
    
    unsigned long int nb=0;
    for (i=0;i < nb_mains;i++) {
        listeMains[i] = (char*)malloc( sizeof(char) * 8 );
        listeMains[i] = strcpy(listeMains[i],une_main);
    }
    
    if (nb_cartes_a_inclure == 6) {
        for (i=0; i<nb_cartes; i++) {
            listeMains[nb++][6] = jeu[i];
        }
    }
    else if (nb_cartes_a_inclure == 5) {
        for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                listeMains[nb][5] = jeu[i];
                listeMains[nb++][6] = jeu[j];
            }
        }
    }
    else if (nb_cartes_a_inclure == 4) {
         for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                for (k=j+1; k<nb_cartes; k++) {
                            listeMains[nb][4] = jeu[i];
                            listeMains[nb][5] = jeu[j];                          
                            listeMains[nb++][6] = jeu[k];
                }
            }
        }        
    }
    else if (nb_cartes_a_inclure == 3) {
         for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                for (k=j+1; k<nb_cartes; k++) {
                    for (l=k+1; l<nb_cartes; l++) {
                        listeMains[nb][3] = jeu[i];
                        listeMains[nb][4] = jeu[j];                          
                        listeMains[nb][5] = jeu[k];                          
                        listeMains[nb++][6] = jeu[l];                          
                    }
                }
            }
        }        
    }
    else if (nb_cartes_a_inclure == 2) {
        //On génère les flops, turns et les rivers
        for (i=0; i<nb_cartes; i++) {
            for (j=i+1; j<nb_cartes; j++) {
                for (k=j+1; k<nb_cartes; k++) {
                    for (l=k+1; l<nb_cartes; l++) {
                        for (m=l+1; m<nb_cartes; m++) {
                            listeMains[nb][2] = jeu[i];
                            listeMains[nb][3] = jeu[j];                          
                            listeMains[nb][4] = jeu[k];                          
                            listeMains[nb][5] = jeu[l];                          
                            listeMains[nb++][6] = jeu[m];                          
                        }
                    }
                }
            }
        }       
    }
    listeMains[nb] = NULL;
    return listeMains;
}

Forces** generationForces(char** mains,unsigned int *nb_forces) {
    
    //Générations des différentes forces
    Forces** distribution_forces = malloc(0);
    unsigned int j = 0;
    unsigned char force_trouvee;
    char* force_symbolique = malloc(7*sizeof(char));
    unsigned long nb_mains,i;
    
    //On calcule le nombre de mains
    for (nb_mains=0;mains[nb_mains]!=NULL;nb_mains++);
    
    
    //Parcours de toutes les mains
    for (i=0;i < nb_mains;i++) {

        force_trouvee = 0;
        
        getForceSymbolique(mains[i],force_symbolique);

        for (j=0;j<(*nb_forces);j++) {
            
            if (strcmp(distribution_forces[j]->force_symbolique,force_symbolique) == 0) {
                force_trouvee = 1;
                distribution_forces[j]->nb += 1;
                break;
            }
            
        }       
        
        //Si on n'a pas trouvé la force, on l'ajoute
        if (force_trouvee == 0) {
            distribution_forces = realloc(distribution_forces,((*nb_forces)+1)*sizeof(Forces*));
            
            distribution_forces[*nb_forces] = malloc(sizeof(Forces));
            distribution_forces[*nb_forces]->force_symbolique = malloc(7 * sizeof(char));
            strcpy(distribution_forces[*nb_forces]->force_symbolique,force_symbolique);
            distribution_forces[*nb_forces]->nb = 1;
            distribution_forces[*nb_forces]->proba = 0.0;
            
            (*nb_forces)++;
        }
        
    }
    free(force_symbolique);
    
    //sort(distribution_forces)
    trierForces(distribution_forces,*nb_forces);
    
    //count(futurs_adversaires)
    unsigned long int nb_mains_total;
    for (nb_mains_total=0;*(mains + nb_mains_total) != NULL;nb_mains_total++);
    
    //On associe la proba d'avoir cette force (proba partielle)
    genererProbasForces(distribution_forces,*nb_forces,nb_mains_total);
    
    return distribution_forces;
    
}

void genererProbasForces(Forces** forces,unsigned int nb_forces,unsigned long nb_mains_total) {
    int i;
    unsigned long nb_mains_battues = 0;
    for (i=(nb_forces - 1);i>=0;i--) {
        forces[i]->proba = (double)nb_mains_battues / (double)nb_mains_total;
        nb_mains_battues += forces[i]->nb;
    }
}
